Skip to main content

全局中间件之 TrustProxies

简介

上一章,我们了解了 第四个 全局中间件 ConvertEmptyStringsToNull 的作用:将空字符串的字段转换为 null

这一章我们了解 最后一个 全局中间件 TrustProxies

从字面意思我们知道是 关于设置信任代理有关的中间件

file

Laravel 官方文档

关于设置信任代理的有关内容--->传送门

通过官方文档,我们知道:

  • 设置信任代理的 IP 地址,以及信任代理发过来的头信息都是在 App\Http\Middleware\TrustProxies 这个最后中间件中实现的。
  • 不知道代理 IP 的情况下,可以用 * 来解决问题

关于什么情况下设置信任代理

当你的站点(Laravel 所在服务器)位于代理服务器(例如:负载均衡)后面的时候,则每个 Web 请求都有可能始终来自该代理,而不是客户端实际在您的站点上发出请求。

此时,你应该根据代理服务设置的转发头以及代理服务器的 IP 地址来配置你的 Laravel 代理信任。

关于为什么要设置信任代理

如果您的站点位于代理(例如负载均衡器)后面,则您的 Web 应用程序可能存在以下一些问题:

  • 重定向和 PHP 生成的 URL 在其 Web 地址,协议和/或端口方面可能不准确。
  • 可能无法为每个用户创建唯一会话,从而导致可能访问不正确的帐户,或者无法让用户完全登录
  • 记录或其他数据收集过程数据可能看起来来自一个位置(代理本身),使您无法区分各个客户端所采取的流量/操作。

关于上面两个为什么的来源

官方扩展包 fideloper/proxy 关于代理的说法--->传送门

正式进入话题

我们来看一下 TrustProxies 是如何进行代理设置的

其 handle 方法在 TrustProxies 父类 Fideloper\Proxy\TrustProxies

Fideloper\Proxy\TrustProxies

<?php

namespace Fideloper\Proxy;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Contracts\Config\Repository;

class TrustProxies
{
//...

/**
* 中间件过滤请求的核心方法
*/
public function handle(Request $request, Closure $next)
{
$request::setTrustedProxies([], $this->getTrustedHeaderNames()); // Reset trusted proxies between requests
$this->setTrustedProxyIpAddresses($request);

return $next($request);
}

/**
* 设置信任代理(例如:负载均衡)的 IP 地址
*/
protected function setTrustedProxyIpAddresses(Request $request)
{
$trustedIps = $this->proxies ?: $this->config->get('trustedproxy.proxies');

// Only trust specific IP addresses
if (is_array($trustedIps)) {
return $this->setTrustedProxyIpAddressesToSpecificIps($request, $trustedIps);
}

// Trust any IP address that calls us
// `**` for backwards compatibility, but is depreciated
if ($trustedIps === '*' || $trustedIps === '**') {
return $this->setTrustedProxyIpAddressesToTheCallingIp($request);
}
}

/**
* 当知道代理服务器 IP 地址时,进行 IP 指定设置
*/
private function setTrustedProxyIpAddressesToSpecificIps(Request $request, $trustedIps)
{
$request->setTrustedProxies((array) $trustedIps, $this->getTrustedHeaderNames());
}

/**
* 当不知道代理服务器 IP 地址时,进行 * 全局设置
*/
private function setTrustedProxyIpAddressesToTheCallingIp(Request $request)
{
$request->setTrustedProxies([$request->server->get('REMOTE_ADDR')], $this->getTrustedHeaderNames());
}

/**
* 获取信任的头信息
*/
protected function getTrustedHeaderNames()
{
return $this->headers ?: $this->config->get('trustedproxy.headers');
}
//...
}

大家可能看到 $request->setTrustedProxies() 方法被调用过好几次,这个方法就是设置信任代理的核心方法,但是非常简单,我们来看一下

Symfony\Component\HttpFoundation\Request

public static function setTrustedProxies(array $proxies, int $trustedHeaderSet)
{
self::$trustedProxies = $proxies;
self::$trustedHeaderSet = $trustedHeaderSet;
}

是不是很简单,就是设置两个静态属性。当后面需要设置重定向,保存日志,设置 session 时,应该会用到这个两个静态属性,具体需要我们一起学到才能知道。

最后,关于官方扩展包的另外一种设置信任 IP 和信任头的方法

  • config/app.php 配置文件中添加服务提供者

    'providers' => array(
    /*
    * 可信代理服务提供者
    */
    Fideloper\Proxy\TrustedProxyServiceProvider::class,
    );
  • 生成 config 配置文件

    $ php artisan vendor:publish --provider="Fideloper\Proxy\TrustedProxyServiceProvider"
  • 替换掉 App\Http\Middleware\TrustProxies 全局中间件

    App\Http\Kernel

    <?php

    namespace App\Http;

    use Illuminate\Foundation\Http\Kernel as HttpKernel;

    class Kernel extends HttpKernel
    {
    protected $middleware = [
    \App\Http\Middleware\CheckForMaintenanceMode::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    \App\Http\Middleware\TrimStrings::class . ':foo,bar',
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    \Fideloper\Proxy\TrustProxies::class, // 原先的是 \App\Http\Middleware\TrustProxies::class,
    ];

    // ...

    }
  • 现在我们就可以在 config 配置文件中进行 代理信任 配置了

    file

写在最后

由于没有用过 Laravel 关于信任代理方面的功能。上面解说,我仅从源代码和相关文档,整理得来,具体使用效果,有经验的童鞋,可以评论区发表出来,大家一起学习。